package jp.tf_web.httpserversample.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.RequestLine;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import android.webkit.MimeTypeMap;

public class HttpServerWorker implements Runnable {
	private final Context _context;
	private final Socket _socket;
	
	public HttpServerWorker(Context context,Socket socket) {
        super();
        this._context = context;
        this._socket = socket;
    }
	
	//受信処理
	public void run() {
		try {
			byte[] req_header_buf= new byte[1024];
			byte[] req_entity_buf  = new byte[10240];
			InputStream is = this._socket.getInputStream();

			//データ受信
			int size = 0;
			HashMap<String,Object> headerList = null;
			for(int i=0;i<=req_header_buf.length;i++){
				int c = is.read();
				if(c == -1) break;
				req_header_buf[i] = (byte)c;
				size++;
				String header_str = new String(req_header_buf,0,size,"UTF8");
				//CRLFCRLFを見つける
				int crlf_index = header_str.indexOf("\r\n\r\n");
				if(crlf_index != -1){
					//ToDo ヘッダー解析 取得
					headerList = HttpUtil.parseRequestHeader(header_str);
					Header header_cl = (Header)headerList.get(HttpUtil.HEADER_NAME_CONTENT_LENGTH);
					if(header_cl == null) break;
					int clen = Integer.parseInt(header_cl.getValue());
					if(clen >= req_entity_buf.length ){
						//ToDo リクエストサイズが起きすぎなのでエラーを返すべき
						break;
					}
					Log.d(this.getClass().getName(),"clen:"+clen);
					
					//メッセージEntityを clen 分 読み込む
					for(int j=0;j<clen;j++){
						int c2 = is.read();
						if(c2 == -1) break;
						req_entity_buf[j] = (byte)c2;
					}
					
					//リクエストパラメータ(POST)
					String entity_str = new String(req_entity_buf,0,clen,"UTF8");
					Log.d(this.getClass().getName(),"entity_str:"+entity_str);
					
					break;
				}
			}
			//headerList = null;
			HttpResponse response = null;
			if(headerList == null){
				//何らかのエラーが発生
				int status_code = 500;
				String reason = "Internal Server Error";
				response = HttpUtil.createHttpResponse(status_code,reason,null);
			}
			else{
				//ToDo ローカルのファイル取得
				RequestLine header_rl = (RequestLine)headerList.get(HttpUtil.HEADER_NAME_REQUESTLINE);
				String uri = sanitizeUri( header_rl.getUri() );
				
				//拡張子からMimeTypeを取得
				String contentType =HttpUtil.getMimeTypeFromUri(uri);
				byte[] file_buf = this.loadLocalFile(uri);
				HttpEntity he = HttpUtil.createHttpEntity(contentType,file_buf);
				
				response = HttpUtil.createHttpResponse(200,"OK",he);	
			}
			//ToDo HttpResponse からレスポンステキストを作れるようにする事
			
			//データ送信
            OutputStream os = this._socket.getOutputStream();
            os.write( response.getStatusLine().toString().getBytes() );
            os.write( "\r\n\r\n".getBytes() );
            if(response.getEntity() != null) {
            	os.write( EntityUtils.toByteArray(response.getEntity()) );
            }
            os.flush();
            
            //ソケットを閉じる
            is.close();
            os.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//URLの無害化
	private String sanitizeUri(final String uri){
		String tmp_uri = uri;
		if( tmp_uri.equals("/") ) tmp_uri = "index.html";		
		//ToDo 1文字目の / を削除する
		if(tmp_uri.indexOf("/") == 0) tmp_uri = tmp_uri.substring(1,uri.length());
		return tmp_uri;
	}
	
	//ローカルのhtmlを読み込む
	private byte[] loadLocalFile(final String uri){
		byte[] file_buf = null;
		
		//ToDo 
		String open_uri = this.sanitizeUri(uri);
		
		Log.d(this.getClass().getName(),"uri:"+open_uri);
		//ToDo SDカードに対応する場合、このへんを書き換える
		AssetManager as = this._context.getResources().getAssets();
		try {
			//1024byt*1000
			//ToDo 必要な分だけメモリを確保するように変更するべき
			file_buf = new byte[1024*1000];
			InputStream is = as.open(open_uri);
			int size = 0;
			for(int i=0;i<file_buf.length;i++){
				int c = is.read();
				if(c == -1) break;
				file_buf[i] = (byte)c;
				size++;
			}
			is.close();
			Log.d(this.getClass().getName(),"size:"+size);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e(this.getClass().getName(),e.getMessage());
		}
		return file_buf;
	}
}
